// 数据
	function TData(k, v, f) {
		this.key = k;
		this.val = v;
		this.fmt = f;
	}
	// 任务参数, 测量点（信息点）, Fn信息类 ,数据
	function TPara(da, dt, datas) {
		this.da = da;
		this.dt = dt;
		this.datas = datas;
	}
	TPara.prototype.add = function(k, v, f) {
		if (!this.datas) this.datas = [];
		this.datas.push(new TData(k, v, f));
	}
	// 任务结果, 标题, 数据
	function TResult(title, datas) {
		this.title = title;
		this.datas = datas;
	}
	TResult.prototype.add = function(k, v, f) {
		if (!this.datas) this.datas = [];
		this.datas.push(new TData(k, v, f));
	}
	//任务 终端地址, AFN, 任务参数数组
	function Task(commAddr, afn, paras) {
		this.commAddr = commAddr;
		this.afn = afn;
		if (isArray(paras)) {
			this.paras = paras;
		} else {
			this.paras = [];
			if (paras) this.paras.push(paras);
		}
	}

	// 规约类
	function UpGw() {
		this.MIN_PACKET_LEN = 16;
		this.MAX_PACKET_LEN = 1024;
		this.HEAD_CHAR = 0x68;
		this.END_CHAR = 0x16;

		this.LEN_POS = 1;
		this.HEAD_POS = 5;
		this.CC_POS = 6;
		this.ADDR_POS = 7;
		this.DATA_LEN_POS = 10;
		this.SEQ_POS = 13;
		this.DATA_POS = 14;
	}
	// 序列号
	UpGw.SeqCode = {
		SimpleT0: 0x70,
		Con0T0: 0x60
	}
	//控制码
	UpGw.CtrlCode = {
		GetData2: 0x4b,
		GetData1: 0x4A
	}
	//功能码
	UpGw.Afn = {
		Control: 05,
		GetConfig: 09,
		GetPara: 10,//
		GetData1: 12,//OCH
		GetData2: 13,
		GetData3: 14,
		properties: {
			10: {
				cc: UpGw.CtrlCode.GetData2,
				sc: UpGw.SeqCode.SimpleT0,
				name: "查询参数"
			},
			12: {
				cc: UpGw.CtrlCode.GetData1,
				sc: UpGw.SeqCode.Con0T0,
				name: "请求1类数据"
			},
			13: {
				cc: UpGw.CtrlCode.GetData2,
				sc: UpGw.SeqCode.Con0T0,
				name: "请求2类数据"
			},
		}
	};
	//用户类别
	UpGw.UserType = {
		Unknown: 0,
		Resident: 5,
		Trans: 6,
		properties: {
			6: {
				name: "考核计量点"
			},
			5: {
				name: "居民用户"
			},
			0: {
				name: "无需设置"
			},
		}
	};
	//表箱规格
	UpGw.WiringId = {
		properties:{
			1: {
				name:"单相"
			},
			3: {
				name:"三相"
			},
			4: {
				name:"分支箱"
			}
		}
	}
	// 报文检查,返回有效帧,否则返回undefined
	UpGw.prototype.searchValid = function(buffer, len) {
		if (len < this.MIN_PACKET_LEN) return null;
		for (i = 0; i <= len - this.MIN_PACKET_LEN; i++) {
			if ((buffer[i + this.CC_POS] >> 7) == 1 &&
				buffer[i] == this.HEAD_CHAR &&
				buffer[i + this.HEAD_POS] == this.HEAD_CHAR) {
				var dataLen = (buffer[i + this.LEN_POS] >> 2) + buffer[i + 1 + this.LEN_POS] * 64;
				var packetEnd = i + dataLen + 7;
				if (len > packetEnd && buffer[packetEnd] == this.END_CHAR) {
					var crc = buffer[packetEnd - 1];
					if (Util.sumCheck(buffer, i + this.CC_POS, i + this.CC_POS + dataLen - 1) == crc) {
						return buffer.subarray(i, packetEnd + 1);
					}
				}
			}
		}
	}
	UpGw.prototype.getCommAddr = function(xb) {
		let commAddr = xb.getBcdStr(this.ADDR_POS, 2);
		commAddr += xb.get(Fmt.Bcd2, this.ADDR_POS + 2);
		return commAddr;
	}
	//根据任务组包
	UpGw.prototype.build = function(task) {
		let xb = new XBuffer(new ArrayBuffer(2024));
		let areaNo = parseInt(task.commAddr.substring(0, 4), 16);
		let termNo = parseInt(task.commAddr.substring(4), 16);

		xb.set(this.HEAD_CHAR);
		xb.set(0, Fmt.Bin4);
		xb.set(this.HEAD_CHAR);
		xb.set(UpGw.Afn.properties[task.afn].cc);
		xb.set(areaNo, Fmt.Bin2);
		xb.set(termNo, Fmt.Bin2);
		xb.set(2); //MasterA3
		xb.set(task.afn);
		xb.set(UpGw.Afn.properties[task.afn].sc);
		for (let i = 0; i < task.paras.length; i++) {
			let para = task.paras[i];
			xb.set(para.da, Fmt.Da);
			xb.set(para.dt, Fmt.Dt);
			if (!para.datas) continue;
			for (let d = 0; d < para.datas.length; d++) {
				let data = para.datas[d];
				xb.set(data.val, data.fmt);
			}
		}
		let len = ((xb.pos - this.CC_POS) << 2) + 2;
		xb.set(len, Fmt.Bin2, this.LEN_POS);
		xb.set(len, Fmt.Bin2, this.LEN_POS + 2);
		let crc = Util.sumCheck(xb.bytes, this.CC_POS, xb.pos);
		xb.set(crc);
		xb.set(this.END_CHAR);
		return xb.bytes.subarray(0, xb.pos);
	}
	//根据任务解析
	UpGw.prototype.parse = function(task, xb) {
		var afn = xb.get(Fmt.Bin1, this.ADDR_POS + 5);
		var addr = this.getCommAddr(xb);
		var result = new TResult(UpGw.Afn.properties[afn].name + " " + addr);
		xb.pos = this.DATA_POS;
		while (xb.bytes.length - xb.pos > 5) {
			var da = xb.get(Fmt.Da);
			var dt = xb.get(Fmt.Dt);
			switch (afn) {
				case UpGw.Afn.GetData1:
					switch (dt) {
						case 2:
							{
								result.add("终端日历时钟", xb.get(Fmt.Data1));
							}
							break;
						case 60:
							{
								let c = xb.get(Fmt.Bin2);
								result.add("配置数量", c);
								for (let i = 1; i <= c; i++) {
									let BoxNo = xb.get(Fmt.Bin2);
									let BoxAddr = xb.get(Fmt.Bcd6);
									xb.pos += 6;
									let WiringId = xb.get(Fmt.Bin1);
									xb.pos += 50;
									let ParentAddr = xb.get(Fmt.Bcd6);
									result.add("父地址" + i, ParentAddr);
									result.add("表箱序号" + i, BoxNo);
									result.add("表箱地址" + i, BoxAddr);
									result.add("表箱规格" + i, Util.getEnmuStr(UpGw.WiringId,WiringId));
									let box = new Box();
									box.getBoxAddr(BoxAddr);
									box.getBoxNo(BoxNo);
									box.getWiringId(WiringId);
									box.getParentAddr(ParentAddr);
									box.save();
								}
							}
							break;
						case 61:
							{
								let c = xb.get(Fmt.Bin2);
								result.add("配置数量", c);
								for (let i = 1; i <= c; i++) {
									let MeterNo = xb.get(Fmt.Bin2);
									let MeterAddr = xb.get(Fmt.Bcd6);
									xb.pos += 1;
									let BoxAddr = xb.get(Fmt.Bcd6);
									result.add("电表序号" + i, MeterNo);
									result.add("电表地址" + i, MeterAddr);
									result.add("所属表箱地址" + i, BoxAddr);
									let boxMeter = new BoxMeter();
									boxMeter.getMeterAddr(MeterAddr);
									boxMeter.getMeterNo(MeterNo);
									boxMeter.getBoxAddr(BoxAddr);
									boxMeter.save();
								}
							}
							break;
					}
					break;
				case UpGw.Afn.GetPara:
					switch (dt) {
						case 10:
							{
								let c = xb.get(Fmt.Bin2);
								result.add("配置数量", c);
								for (let i = 1; i <= c; i++) {
									xb.pos += 2;
									let DA = xb.get(Fmt.Bin2);
									xb.pos += 2;
									let MeterAddr = xb.get(Fmt.Bcd6);
									xb.pos += 14;
									let mutype = xb.get(Fmt.Bin1);
									let ut = (mutype & 0xF0) >> 4;
									let mt = (mutype & 0x0F);
									result.add("用户类别" + i, Util.getEnmuStr(UpGw.UserType,ut));
									result.add("测量点号" + i, DA);
									result.add("通信地址" + i, MeterAddr);
									let meter = new Meter();
									meter.getMeterAddr(MeterAddr);
									meter.getDA(DA);
									meter.getUserTypeId(ut);
									meter.getMeterTypeId(mt);
									meter.getMeterName('表'+DA);
									meter.save();
									
								}
							}
							break;
					}
					break;
			}
		}
		return result;
	}
